package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/des"
)

//明文填充
func padding(proclaimed []byte, blocksize int) []byte {
	//填充明文最后一个分组
	//1、获取欠缺的分组长度需要多长
	padNum := blocksize - len(proclaimed)%blocksize
	//2、创建新的切片，长度为1，值为byte（padNum）
	char := []byte{byte(padNum)}
	//3、长度为padNum    byte.Repeat可以把char重复padNum次，然后连接成为新的切片
	newplain := bytes.Repeat(char, padNum)
	//4、在明文后面追加newplain，append中追加的是另一个切片时，需要如下添加"..."
	newText := append(proclaimed, newplain...)
	return newText
}

//明文去除填充：因为填充这个操作，不管后面的长度是否够一个分组，
//假设有28 % 8 =3……4 这种需要填充
//但是如果24 % 8 =3 这种没有多出来的，也需要补一个分组，即24加填充的8等于32
//因此，去除填充就可以进行如下的操作，拿明文的最后一个字符作为线索反填充。
func unpadding(proclaimed []byte) []byte {
	lastPs := len(proclaimed) - 1
	last := proclaimed[lastPs]
	lastint := int(last)
	return proclaimed[:len(proclaimed)-lastint]
}

//des使用cbc分组模式加密
func desEncrypt(proclaimed []byte, key []byte) []byte {
	//创建一个des加密的接口
	block, err := des.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//对明文进行填充
	padText := padding(proclaimed, block.BlockSize())
	//创建一个初始化常量
	iv := []byte("12345678")
	//使用CBC分组模式接口
	cbcmode := cipher.NewCBCEncrypter(block, iv)
	//直接给明文加密
	cbcmode.CryptBlocks(padText, padText)
	return padText
}

//des基于CBC模式解密操作
func desDecrypt(proclaimed []byte, key []byte) []byte {
	//创建一个des加密的接口
	block, err := des.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//创建一个初始化常量
	iv := []byte("12345678")
	//使用CBC分组模式接口
	cbcmode := cipher.NewCBCDecrypter(block, iv)
	//直接给明文解密
	cbcmode.CryptBlocks(proclaimed, proclaimed)
	//对明文进行反填充
	padText := unpadding(proclaimed)
	return padText
}

//aes使用CTR模式进行加密
func aesEncrypt(proclaimed []byte, key []byte) []byte {
	//创建一个aes密码的接口
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//创建一个初始化常量
	iv := []byte("12345678asdasdzz")
	//使用CTR分组模式接口,返回的是一个数据流
	stream := cipher.NewCTR(block, iv)
	//直接给明文加密
	stream.XORKeyStream(proclaimed, proclaimed)

	return proclaimed
}

//aes使用CTR模式进行解密
func aesDecrypt(proclaimed []byte, key []byte) []byte {
	//创建一个aes密码的接口
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//创建一个初始化常量
	iv := []byte("12345678asdasdzz")
	//使用CTR分组模式接口,返回的是一个数据流
	stream := cipher.NewCTR(block, iv)
	//直接给明文解密
	stream.XORKeyStream(proclaimed, proclaimed)
	return proclaimed
}
